package model

import (
	"fmt"
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/facade/env"
	"gitee.com/sansaniot/ssiot-core/httpmvc/model"
	"github.com/bytedance/sonic"

	"ssdevice/common/constant"
	"ssdevice/common/dto"
	"ssdevice/internal/rule/model/query"
)

const RuleEnable = "enable"
const RuleDisable = "disable"
const RuleCacheKeyPrefix = "dev_rule"
const RuleProductCacheKeyPrefix = "product_rule"
const RuleChainKey = "rule"

type Rule struct {
	Id         string        `json:"id"`
	Name       string        `json:"name"`
	Desc       string        `json:"desc" `
	ProductId  string        `json:"productId"`
	Creator    string        `json:"creator"`
	Status     string        `json:"status"`
	DevSn      string        `json:"devSn"`
	AgencyId   string        `json:"agency_id"`
	CreateTime dto.LocalTime `json:"createTime"`
	UpdateTime dto.LocalTime `json:"updateTime"`
	model.Model
}

func (r *Rule) GetById(id string) error {
	err := r.Orm.Where(Rule{Id: id}).First(r).Error
	return err
}

func (r *Rule) GetOne(q *query.RuleGetReq) error {
	where := dto.MakeCondition(q.GetNeedSearch())
	err := r.FindOne(r, where)
	r.Creator = q.UserName
	return err
}

func (r *Rule) FindEnabled() ([]*Rule, error) {
	list := make([]*Rule, 0)

	err := r.Orm.Model(r).Where(Rule{Status: RuleEnable}).Find(&list).Error

	return list, err
}

// FindPage 获取微服务列表
func (r *Rule) FindPage(q *query.RuleGetReq) (result interface{}, count int64, err error) {
	list := make([]*Rule, 0)
	where := dto.MakeCondition(q.GetNeedSearch())

	err = r.Orm.Model(r).Scopes(
		where,
		dto.OrderDest("create_time", true, q.OrderBy),
		dto.Paginate(q.GetPageSize(), q.GetPageIndex()),
	).Find(&list).Limit(-1).Offset(-1).Count(&count).Error

	user := &User{}
	user.Orm = r.Orm

	for _, l := range list {
		user.Id = l.Creator
		_ = user.getName()
		l.Creator = user.Username
		user.Username = ""
	}

	return list, count, nil
}

func (r *Rule) AddRule() error {
	err := r.Add(r)
	return err
}

func (r *Rule) Enable() error {
	err := r.GetById(r.Id)
	if err != nil {
		return err
	}

	r.Status = RuleEnable
	r.UpdateTime = dto.LocalTime(time.Now())

	err = r.Mod(r)
	r.setRuleCache()

	return err
}

func (r *Rule) setRuleCache() {
	// 查询处理器
	processor := Processor{}
	processor.Model = r.Model
	list := processor.FindChainsByRule(r.Id)

	//	设置缓存
	devSlice := make([]string, 0)
	if len(r.DevSn) > 0 {
		devSlice = strings.Split(r.DevSn, ",")
	}
	for _, d := range devSlice {
		cacheKey := fmt.Sprintf("%s:%s", RuleCacheKeyPrefix, d)
		cacheValue, _ := sonic.Marshal(list)
		_ = env.Cache.HashSet(cacheKey, RuleChainKey, cacheValue)
		_ = env.Cache.HashSet(cacheKey, "name", r.Name)
		_ = env.Cache.HashSet(cacheKey, "id", r.Id)
	}
	// 设置产品缓存
	productSlice := make([]string, 0)
	if len(r.ProductId) > 0 {
		productSlice = strings.Split(r.ProductId, ",")
	}
	for _, d := range productSlice {
		cacheKey := fmt.Sprintf("%s:%s", RuleProductCacheKeyPrefix, d)
		cacheValue, _ := sonic.Marshal(list)
		_ = env.Cache.HashSet(cacheKey, RuleChainKey, cacheValue)
		_ = env.Cache.HashSet(cacheKey, "name", r.Name)
		_ = env.Cache.HashSet(cacheKey, "id", r.Id)
	}
}

func (r *Rule) Disable() error {
	err := r.GetById(r.Id)
	if err != nil {
		return err
	}

	r.Status = RuleDisable
	r.UpdateTime = dto.LocalTime(time.Now())

	err = r.Mod(r)

	r.delRuleCache()

	return err
}

func (r *Rule) delRuleCache() {
	//	删除缓存
	devSlice := strings.Split(r.DevSn, ",")

	for _, d := range devSlice {
		cacheKey := fmt.Sprintf("%s:%s", RuleCacheKeyPrefix, d)
		_ = env.Cache.Del(cacheKey)
	}
	//删除产品缓存
	productSlice := make([]string, 0)
	if len(r.ProductId) > 0 {
		productSlice = strings.Split(r.ProductId, ",")
	}
	for _, d := range productSlice {
		cacheKey := fmt.Sprintf("%s:%s", RuleProductCacheKeyPrefix, d)
		_ = env.Cache.Del(cacheKey)
	}
}

func (r *Rule) Modify(updates map[string]interface{}) error {
	err := r.ModMap(r, updates)
	if err != nil {
		return err
	}

	// 启用状态时更新缓存
	err = r.GetById(r.Id)
	if err != nil {
		return err
	}

	if r.Status == constant.RuleEnable {
		r.delRuleCache()
		r.setRuleCache()
	}

	return err
}

func (r *Rule) Remove() error {
	_ = r.Delete(r)
	processor := Processor{}
	processor.Model = r.Model
	processor.RuleId = r.Id
	processor.RemoveByRuleId()
	return nil
}

func (r *Rule) TableName() string {
	return "sys_rule"
}

func (r *Rule) GetId() interface{} {
	return r.Id
}
